package mushystuff.dtb.core.model;

import java.util.SortedSet;
import java.util.TreeSet;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;

@Entity
public class UserStory extends PersistableBean implements Comparable<UserStory> {

    public enum Priority {
        CRITICAL(50), HIGH(30), MEDIUM(20), LOW(10);

        private int level;

        Priority(int level) {
            this.level = level;
        }

        public int getLevel() {
            return level;
        }
    }

    public enum Estimate {
        UNKOWN(-1), ZERO(0), HALF(0.5), ONE(1), TWO(2), THREE(3), FIVE(5), EIGHT(
                8), THIRTEEN(13), TWEENTY(20), FOURTY(40), ONE_HUNDRED(100);

        private double storyPoints;

        Estimate(double storyPoints) {
            this.storyPoints = storyPoints;
        }

        public double getStoryPoints() {
            return storyPoints;
        }
    }

    private String story;

    private String test;

    private String notes;

    private Estimate estimate;

    private Priority priority;

    private Sprint assignedSprint;

    private Product product;

    private SortedSet<Task> tasks = new TreeSet<Task>();

    public UserStory() {
        super();
        priority = Priority.MEDIUM;
        estimate = Estimate.ONE;
        story = StringUtils.EMPTY;
    }

    @Column(length = 255, nullable = false)
    public String getStory() {
        return story;
    }

    public void setStory(final String story) {
        this.story = story;
    }

    @Column(length = 255)
    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

    @Column(length = 255)
    public String getNotes() {
        return notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    @Column(nullable = false)
    public Estimate getEstimate() {
        return estimate;
    }

    public void setEstimate(Estimate estimate) {
        this.estimate = estimate;
    }

    @Column(nullable = false)
    public Priority getPriority() {
        return priority;
    }

    public void setPriority(final Priority priority) {
        this.priority = priority;
    }

    @ManyToOne
    public Sprint getAssignedSprint() {
        return assignedSprint;
    }

    public void setAssignedSprint(Sprint assignedSprint) {
        this.assignedSprint = assignedSprint;
    }

    @ManyToOne(optional = false)
    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    @OneToMany
    @Sort(type = SortType.NATURAL)
    public SortedSet<Task> getTasks() {
        return tasks;
    }

    public void setTasks(SortedSet<Task> tasks) {
        this.tasks = tasks;
    }

    @Override
    public int compareTo(final UserStory o) {
        int res;
        if (this.getPriority() == o.getPriority()) {
            res = getStory().compareTo(o.getStory());
        } else {
            res = o.getPriority().getLevel() - getPriority().getLevel();
        }
        return res;
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (obj.getClass() != getClass()) {
            return false;
        }
        UserStory rhs = (UserStory) obj;
        return new EqualsBuilder().append(story, rhs.story).append(product,
                rhs.product).isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(41, 3).append(story).append(product)
                .toHashCode();

    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("story", story).append(
                "priority", priority).append("estimate", estimate)
                .append("assignedSprint", assignedSprint).append("product",
                        product).toString();
    }

}
